package org.example.erat.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.example.erat.dto.StudentDTO;
import org.example.erat.entity.ClassEntity;
import org.example.erat.entity.Student;
import org.example.erat.exception.ResourceNotFoundException;
import org.example.erat.repository.ClassRepository;
import org.example.erat.repository.StudentRepository;
import org.example.erat.service.StudentService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 学生服务实现类
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class StudentServiceImpl implements StudentService {

    private final StudentRepository studentRepository;
    private final ClassRepository classRepository;

    @Override
    @Transactional
    public StudentDTO createStudent(StudentDTO studentDTO) {
        log.info("创建学生: {}", studentDTO.getName());

        ClassEntity classEntity = classRepository.findById(studentDTO.getClassId())
                .orElseThrow(() -> new ResourceNotFoundException("班级不存在: " + studentDTO.getClassId()));

        // 检查学号是否已存在
        studentRepository.findByStudentId(studentDTO.getStudentId())
                .ifPresent(s -> {
                    throw new IllegalArgumentException("学号已存在: " + studentDTO.getStudentId());
                });

        Student student = Student.builder()
                .studentId(studentDTO.getStudentId())
                .name(studentDTO.getName())
                .grade(studentDTO.getGrade())
                .major(studentDTO.getMajor())
                .classEntity(classEntity)
                .build();

        Student savedStudent = studentRepository.save(student);
        return convertToDTO(savedStudent);
    }

    @Override
    @Transactional
    public StudentDTO updateStudent(Long id, StudentDTO studentDTO) {
        log.info("更新学生: {}", id);

        Student student = studentRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("学生不存在: " + id));

        ClassEntity classEntity = classRepository.findById(studentDTO.getClassId())
                .orElseThrow(() -> new ResourceNotFoundException("班级不存在: " + studentDTO.getClassId()));

        // 检查学号是否已被其他学生使用
        studentRepository.findByStudentId(studentDTO.getStudentId())
                .ifPresent(s -> {
                    if (!s.getId().equals(id)) {
                        throw new IllegalArgumentException("学号已存在: " + studentDTO.getStudentId());
                    }
                });

        student.setStudentId(studentDTO.getStudentId());
        student.setName(studentDTO.getName());
        student.setGrade(studentDTO.getGrade());
        student.setMajor(studentDTO.getMajor());
        student.setClassEntity(classEntity);

        Student updatedStudent = studentRepository.save(student);
        return convertToDTO(updatedStudent);
    }

    @Override
    @Transactional
    public void deleteStudent(Long id) {
        log.info("删除学生: {}", id);

        Student student = studentRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("学生不存在: " + id));

        studentRepository.delete(student);
    }

    @Override
    public StudentDTO getStudent(Long id) {
        log.info("获取学生: {}", id);

        Student student = studentRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("学生不存在: " + id));

        return convertToDTO(student);
    }

    @Override
    public List<StudentDTO> getAllStudents() {
        log.info("获取所有学生");

        List<Student> students = studentRepository.findAll();
        return students.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public List<StudentDTO> getStudentsByClass(Long classId) {
        log.info("获取班级的学生列表: {}", classId);

        ClassEntity classEntity = classRepository.findById(classId)
                .orElseThrow(() -> new ResourceNotFoundException("班级不存在: " + classId));

        List<Student> students = studentRepository.findByClassEntity(classEntity);
        return students.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public List<StudentDTO> importStudentsFromExcel(Long classId, MultipartFile file) {
        log.info("从Excel导入学生到班级: {}", classId);

        ClassEntity classEntity = classRepository.findById(classId)
                .orElseThrow(() -> new ResourceNotFoundException("班级不存在: " + classId));

        List<Student> importedStudents = new ArrayList<>();

        try (InputStream is = file.getInputStream()) {
            Workbook workbook = WorkbookFactory.create(is);
            Sheet sheet = workbook.getSheetAt(0);
            Iterator<Row> rows = sheet.iterator();

            // 跳过表头
            if (rows.hasNext()) {
                rows.next();
            }

            while (rows.hasNext()) {
                Row row = rows.next();

                String studentId = getCellValueAsString(row.getCell(0));
                String name = getCellValueAsString(row.getCell(1));
                String grade = getCellValueAsString(row.getCell(2));
                String major = getCellValueAsString(row.getCell(3));

                // 检查必填字段
                if (studentId == null || studentId.isEmpty() || name == null || name.isEmpty()) {
                    continue;
                }

                // 检查学号是否已存在
                if (studentRepository.findByStudentId(studentId).isPresent()) {
                    log.warn("学号已存在，跳过导入: {}", studentId);
                    continue;
                }

                Student student = Student.builder()
                        .studentId(studentId)
                        .name(name)
                        .grade(grade)
                        .major(major)
                        .classEntity(classEntity)
                        .build();

                importedStudents.add(student);
            }

            // 批量保存学生
            List<Student> savedStudents = studentRepository.saveAll(importedStudents);
            return savedStudents.stream()
                    .map(this::convertToDTO)
                    .collect(Collectors.toList());

        } catch (IOException e) {
            log.error("导入Excel文件失败", e);
            throw new RuntimeException("导入Excel文件失败: " + e.getMessage());
        }
    }

    /**
     * 获取单元格的字符串值
     * @param cell 单元格
     * @return 字符串值
     */
    private String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    // 将数字转换为字符串，避免科学计数法
                    return String.valueOf((long) cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }

    /**
     * 将学生实体转换为DTO
     * @param student 学生实体
     * @return 学生DTO
     */
    private StudentDTO convertToDTO(Student student) {
        return StudentDTO.builder()
                .id(student.getId())
                .studentId(student.getStudentId())
                .name(student.getName())
                .grade(student.getGrade())
                .major(student.getMajor())
                .classId(student.getClassEntity().getId())
                .className(student.getClassEntity().getName())
                .build();
    }
}
